﻿namespace FODATAC

open System.Linq
open FODATAC.Interfaces.Internal
open System.Linq.Expressions
open System.Runtime.CompilerServices
open System.Linq.Expressions
open System.Reflection
open System.Threading.Tasks
open FODATAC.Interfaces

[<Extension>]
type ExtraCSharpStyleExtensionMethodsInFSharp() = 
    
    [<Extension>]
    static member inline ToListAsync(queryable : IQueryable<'T>) = 
        match queryable with
        | :? IODataQueryable<'T> as quer -> quer.ToListAsync()
        | _ -> failwith "this IQueryable doesn't support ToListAsync"


    [<Extension>]
    static member inline FirstAsync(queryable : IQueryable<'T>) :Task<'T> = 
        match queryable with
        | :? IODataQueryable<'T> as quer ->  (quer.Take(1) :?> IODataQueryable<'T>).FirstAsync()
        | _ -> failwith "this IQueryable doesn't support FirstAsync"

    [<Extension>]
    static member inline FirstAsync(queryable : IQueryable<'T>,  predicate : Expression<System.Func<'T, bool>>) = 
        match queryable with
        | :? FODATAC.Interfaces.IODataQueryable<'T> as quer -> quer.Where(predicate) |> ExtraCSharpStyleExtensionMethodsInFSharp.FirstAsync
        | _ -> failwith "this IQueryable doesn't support FirstAsync"
    
    [<Extension>]
    static member inline FirstOrDefaultAsync(queryable : IQueryable<'T>) :Task<'T> = 
        match queryable with
        | :? FODATAC.Interfaces.IODataQueryable<'T> as quer -> (quer.Take(1) :?> IODataQueryable<'T>).FirstOrDefaultAsync()
        | _ -> failwith "this IQueryable doesn't support FirstOrDefaultAsync"

    [<Extension>]
    static member inline FirstOrDefaultAsync(queryable : IQueryable<'T>,  predicate : Expression<System.Func<'T, bool>>) = 
        match queryable with
        | :? FODATAC.Interfaces.IODataQueryable<'T> as quer -> quer.Where(predicate) |> ExtraCSharpStyleExtensionMethodsInFSharp.FirstOrDefaultAsync
        | _ -> failwith "this IQueryable doesn't support FirstOrDefaultAsync"
    

    

    [<Extension>]
    static member inline Fetch(queryable : IQueryable<'T>, fetchExpression : Expression<System.Func<'T, obj>>) = 
        let provider = queryable.Provider
        let mi = 
            typeof<ExtraCSharpStyleExtensionMethodsInFSharp>.GetRuntimeMethods() |> Seq.find (fun c-> c.Name = "Fetch")
        let mi = mi.MakeGenericMethod([| typeof<'T> |])
        
        let expArray = 
            [| queryable.Expression
               Expression.Quote(fetchExpression) :> Expression |]
        provider.CreateQuery<'T>(Expression.Call(null, mi, expArray))
